/*
    Copyright 2009 Barnet Wagman

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
 */

package ot;

import java.io.*;
import java.util.zip.*;

/** <tt>GzipSerializer</tt> produces compressed serialized objects.
 *  Compression is performed using <tt>java.util.zip.GZIPInputStream</tt>.
 *
 * @author Barnet Wagman
 */
public class GzipSerializer implements Serializer {

    public transient int sizeBytesLastDesrialized;
    
    static int READ_BLOCK_SIZE = 1024 * 512;

        /**
         *
         * @return {@link ConstantsOt#GZSER}
         */
    public String getObjectNameExtension() {
        return(ConstantsOt.GZSER);
    }

        /** {@inheritDoc}
         * 
         * @param B
         * @return
         * @throws ot.OtException
         */
    public Serializable byteArrayToObject(byte[] B)             
        throws OtException {

        ByteArrayInputStream baos = null;
        GZIPInputStream gis = null;
        ByteArrayInputStream unzippedBaos = null;
        ObjectInputStream ois = null;
        try {                       
            baos = new ByteArrayInputStream(B,0,B.length);	   	    
            gis = new GZIPInputStream(baos);
            ois = new ObjectInputStream(gis);
                    
            return( (Serializable) ois.readObject() );            
        }
        catch ( Exception x ) {            
            throw new OtException(x);
        }      
        finally {            
            try {
                if ( ois != null ) { ois.close(); ois = null; }
                if ( unzippedBaos != null ) { 
                    unzippedBaos.close();
                    unzippedBaos = null;
                } 
                if ( gis != null ) { gis.close(); gis = null; }
                if ( baos != null ) { baos.close(); baos = null; }
            }
            catch(IOException iox) { throw new OtException(iox); }
        }
    }
    
    public int getSizeOfLastDeserializedObject() {
         return(sizeBytesLastDesrialized);
    }

        /** {@inheritDoc}
         *
         * @param obj
         * @return
         * @throws ot.OtException
         */
    public byte[] objectToByteArray(Serializable obj) throws OtException {
        
        ByteArrayOutputStream baos = null;
        GZIPOutputStream gos = null;
        ObjectOutputStream oos = null;
        try {   
	    baos = new ByteArrayOutputStream();	
        gos = new GZIPOutputStream(baos);
	    oos = new ObjectOutputStream(gos);
	    oos.writeObject(obj);            
	    gos.finish();                       
        byte[] b = baos.toByteArray();
        return(b);
	}        
	catch (java.io.IOException iox) { throw new OtException(iox); }
        finally {
            try {
                if ( oos != null ) { oos.close(); oos = null; }
                if ( gos != null ) { gos.close(); gos = null; }
                if ( baos != null ) { baos.close(); baos = null; }
                /* ^^^^^^^^ WARNING-Java BUG! when serializing large objects
                 * the baos seems to leak memory.  When this method returns
                 * baos is unreferenced and SHOULD get all its space freed up,
                 * but it does not appear to, unless we explicitly null it out.
                 */
            }
            catch(IOException iox) { throw new OtException(iox); }
        }
    }
        
    public static class ObjectInputStreamWithPrimitiveSupport 
        extends ObjectInputStream {
        
        public ObjectInputStreamWithPrimitiveSupport(InputStream is) 
            throws IOException, StreamCorruptedException {
            super(is);
        }

        public Class resolveClass(ObjectStreamClass desc)
            throws ClassNotFoundException, IOException {             
            try {
                return super.resolveClass(desc);
            } catch (ClassNotFoundException e) {
                String nm = desc.getName();
                if (nm.equals("int")) return int.class;
                if (nm.equals("long")) return long.class;
                if (nm.equals("float")) return float.class;
                if (nm.equals("double")) return double.class;
                if (nm.equals("char")) return char.class;
                if (nm.equals("boolean")) return boolean.class;
                if (nm.equals("short")) return short.class;
                if (nm.equals("byte")) return byte.class;
                else /* check for other primitive types if one wishes.*/
                    throw e;
            }
        }                
    }

        /** {@inheritDoc}
         * 
         * @param f
         * @return
         * @throws ot.OtException
         */
    public Object fileToObject(File f) throws OtException {
        FileInputStream fis = null;
        GZIPInputStream gis = null;
        ObjectInputStream oos = null;
        try {   
            fis = new FileInputStream(f);
            gis = new GZIPInputStream(fis);
            Object obj = new Object();            
            oos = new ObjectInputStream(gis);	            
            obj = oos.readObject();
            return(obj);
        }
        catch ( Exception x ) {  throw new OtException(x); }
        finally {
            try {
                if ( oos != null ) oos.close();
                if ( gis != null ) gis.close();
                if ( fis != null ) fis.close();
            }
            catch ( Exception x ) {  throw new OtException(x); }
        }
    }

        /** {@inheritDoc}
         *
         * @param f
         * @param obj
         * @throws ot.OtException
         */
    public void objectToFile(File f, Serializable obj) throws OtException {
        
         FileOutputStream fos = null;
         GZIPOutputStream gos = null;
         ObjectOutputStream oos = null;
         try {
            fos = new FileOutputStream(f);
            gos = new GZIPOutputStream(fos);
            oos = new ObjectOutputStream(gos);
            oos.writeObject(obj);
            gos.finish();            
        }
        catch (java.io.IOException iox) {
            throw new OtException("Serialization.objectToFile(): "
                            + "error occurred writing object to file:"
                            + iox.toString());
        }
        finally {
            try {
                if ( oos != null ) oos.close();
                if ( gos != null ) gos.close();
                if ( fos != null ) fos.close();
            }
            catch ( Exception x ) {  throw new OtException(x); }
        }
    }    
}
